﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using System.Threading;
using Common.Logging;
using In.Api.Dto.HisWs;
using In.Api.Dto.YBWs;
using Newtonsoft.Json;
using Out.Service.Helpers;
using Out.Service.HttpClients;
using OutDbContext;
using Rmq.Center;

namespace Out.Service.Services
{
    public class BizBillOrder:IDisposable
    {
        //支付状态：0未支付 1支付中 2支付成功 3支付失败 4退款中 
        //5退款成功 6退款失败 7缴费中 8缴费成功 9缴费失败
        public enum OrderStatus
        {
            未支付 = 0,
            支付中 = 1,
            支付成功 = 2,
            支付失败 = 3,
            退款中 = 4,
            退款成功 = 5,
            退款失败 = 6,
            缴费中 = 7,
            缴费成功 = 8,
            缴费失败 = 9
        }


        /// <summary>
        /// 支付状态:0-未付款,1-已付款,2-退款中,3-已退款,4-退款失败
        /// </summary>
        public enum PayState
        {
            未付款 = 0,
            已付款 = 1,
            退款中 = 2,
            已退款 = 3,
            退款失败 = 4
        }


        private static readonly ILog Logger = LogManager.GetLogger(typeof(BizBillOrder));

        private static readonly object OrderNoLocker = new object();

        private readonly GdsfybjyWeiXinEntities _ctx;
        private int _orderId;
        private readonly string _openId;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="openId">用户openid</param>
        public BizBillOrder(string openId = "")
        {
            _ctx = new GdsfybjyWeiXinEntities();
            _openId = openId;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="orderId">订单Id</param>
        /// <param name="openId">用户openid</param>
        public BizBillOrder(int orderId, string openId = "")
        {
            _ctx = new GdsfybjyWeiXinEntities();
            _orderId = orderId;
            _openId = openId;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="orderNo">订单号</param>
        /// <param name="openId">用户openid</param>
        public BizBillOrder(string  orderNo, string openId = "")
        {
            _ctx = new GdsfybjyWeiXinEntities();
            var order = _ctx.BillOrders.FirstOrDefault(x => x.OrderNo == orderNo);
            if (order != null) _orderId = order.Id;
            _openId = openId;
        }

        /// <summary>
        /// 获取订单数据对象
        /// </summary>
        /// <returns></returns>
        public BillOrder GetBillOrder()
        {
            var order = _ctx.BillOrders.FirstOrDefault(x => x.Id == _orderId);
            return order;
        }

        /// <summary>
        /// 获取订单明细列表
        /// </summary>
        /// <returns></returns>
        public List<BillOrderItem> GetBillOrderItems()
        {
            return _ctx.BillOrderItems.Where(x => x.BillOrderId == _orderId).ToList();
        }

        /// <summary>
        /// 获取订单指引
        /// </summary>
        /// <returns></returns>
        public List<BillOrderDisWin> GetBillOrderDisWin()
        {
            return _ctx.BillOrderDisWins.Where(x => x.BillOrderId == _orderId).ToList();
        }

        /// <summary>
        /// 获取制定时间缴费单列表
        /// </summary>
        /// <param name="startDt">开始时间</param>
        /// <param name="endDt">结束时间</param>
        /// <returns></returns>
        public IQueryable<BillOrder> GetOrderList(DateTime startDt,DateTime endDt)
        {
            var orders = _ctx.BillOrders.IsOpenId(_openId).IsStatus(OrderStatus.缴费成功)
                .Where(x => x.CreateTime >= startDt && x.CreateTime < endDt).OrderByDescending(x => x.CreateTime);

            return orders;
        }

        /// <summary>
        /// 生成缴费订单单号
        /// </summary>
        /// <returns></returns>
        public string GenerateNewOrderNo()
        {
            var orderNo = "WX" + DateTime.Now.Date.ToString("yyyyMMdd");
            lock (OrderNoLocker)
            {
                orderNo += (DateTime.Now - DateTime.Now.Date).TotalMilliseconds.ToString("00000000");
                Thread.Sleep(1);
            }

            return orderNo;
        }

        /// <summary>
        /// 根据就诊卡号得到待缴费单据列表
        /// </summary>
        /// <param name="cardNo">就诊卡号</param>
        public ResResult<GetPrescriptionListResponse> GetBillList(string cardNo)
        {
            //获取院内webservice
            var request = new GetPrescriptionListRequest();
            request.CardNo = cardNo;

            GetPrescriptionListResponse response;
            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisWs/GetPrescriptionList", request).Result;
                responseMsg.EnsureSuccessStatusCode();
                response = responseMsg.Content.ReadAsAsync<GetPrescriptionListResponse>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内获取缴费单Api出错,信息：{0}", JsonConvert.SerializeObject(ex));

                return new ResResult<GetPrescriptionListResponse>(Result.未返回);
            }
            if (response.ResultCode == "0")
            {
                return new ResResult<GetPrescriptionListResponse>(Result.成功, response);
            }
            else
            {
                return new ResResult<GetPrescriptionListResponse>(Result.失败,response, "没有查询到您的缴费单信息");
                
            }

        }

        /// <summary>
        /// 生成门诊缴费单
        /// </summary>
        /// <param name="cardNo">就诊卡号</param>
        /// <param name="cardType">卡类型</param>
        /// <param name="clinicNo">就诊流水号</param>
        /// <param name="orderDate">日期</param>
        /// <param name="orderDept">科室</param>
        /// <param name="zfjf">手动选择自费则传入</param>
        /// <param name="prescMoney">缴费金额</param>
        /// <returns></returns>
        public ResResult<PrescriptionResponse> CreateBillOrder(string cardNo,string cardType,string clinicNo,string orderDate, string prescMoney,string orderDept, bool zfjf)
        {
            //获取院内webservice
            var request = new GetPrescriptionDetailRequest();
            request.PrescNo = clinicNo;
            request.CardNo = cardNo;

            GetPrescriptionDetailResponse response;
            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisWs/GetPrescriptionDetail", request).Result;
                responseMsg.EnsureSuccessStatusCode();
                response = responseMsg.Content.ReadAsAsync<GetPrescriptionDetailResponse>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内获取缴费单明细Api出错,信息：{0}", JsonConvert.SerializeObject(ex));
                
                return new ResResult<PrescriptionResponse>(Result.未返回, "调用院内获取缴费单明细服务出错");
            }
            PrescriptionResponse prescriptionResponse = new PrescriptionResponse
            {
                IsGetBillDetailInfoSucceed = false,
                PrescItemList = response.PrescItemList
            };
            if (response.ResultCode == "0")
            {
                //订单状态：0未支付 1支付中 2支付成功 3支付失败 4退款中 5退款成功 6退款失败 7缴费中 8缴费成功 9缴费失败
                //为了避免医生 在同一个 就诊流水号 上再次开单造成患者无法支付的情况，对于 未支付 和 缴费成功 的情况我们可以 再次生成订单

                var billOrder = _ctx.BillOrders.IsStatus(OrderStatus.支付中).FirstOrDefault(x =>
                        x.CardType == cardType
                        && x.CardNo == cardNo
                        && x.ClinicNo == clinicNo
                        && x.OrderDate == orderDate);
                if (billOrder != null)
                {
                    _orderId = billOrder.Id;
                    CancelPay();
                }

                billOrder = _ctx.BillOrders.IsStatus(OrderStatus.支付成功, OrderStatus.缴费中).FirstOrDefault(x =>
                      x.CardType == cardType
                      && x.CardNo == cardNo
                      && x.ClinicNo == clinicNo
                      && x.OrderDate == orderDate);
                if (billOrder != null)
                {
                    //已有正在缴费订单，直接返回
                    prescriptionResponse.BillOrderId = billOrder.Id;
                    prescriptionResponse.BillOrderNo = billOrder.OrderNo;
                    prescriptionResponse.ErrMsg = "系统正在处理您的订单请耐心等候，大约需要15分钟";
                    return new ResResult<PrescriptionResponse>(Result.失败, prescriptionResponse);
                }
                else
                {
                    #region 获取就诊卡信息(判断是否可使用广州医保)

                    var request4patient = new GetPatientInfoRequest();
                    request4patient.CardNo = cardNo;
                    request4patient.CardType = cardType;
                    GetPatientInfoResponse patientResponse;
                    try
                    {
                        var httpClient = InHttpClient.GetClient();
                        var responseMsg = httpClient.PostAsJsonAsync("HisWs/GetPatientInfo", request4patient).Result;
                        responseMsg.EnsureSuccessStatusCode();
                        patientResponse = responseMsg.Content.ReadAsAsync<GetPatientInfoResponse>().Result;
                    }
                    catch (Exception ex)
                    {
                        Logger.ErrorFormat("调用院内获取病人信息Api出错,信息：{0}", JsonConvert.SerializeObject(ex));
                        prescriptionResponse.ErrMsg = "服务器或网络异常，请联系客服！";
                        return new ResResult<PrescriptionResponse>(Result.失败, prescriptionResponse);
                    }
                    if (patientResponse.ResultCode == "0")
                    {
                        var newOrderNo = GenerateNewOrderNo();
                        var newBillOrder = new BillOrder
                        {
                            OpenId = _openId,
                            CardNo = cardNo,
                            CardType = cardType,
                            ClinicNo = clinicNo,
                            OrderNo = newOrderNo,
                            OrderDate = orderDate,
                            OrderDept = orderDept,
                            OrderStatus = OrderStatus.未支付.ToInt32(),
                            PrescMoney = prescMoney.ToDecimalOrDefault(),
                            PayState = PayState.未付款.ToInt32().ToString(),
                            CreateTime = DateTime.Now,
                        };

                        var isYB=patientResponse.PatientInfo.FeeType == "广州医保" && prescMoney.ToDecimalOrDefault() > 0 && !zfjf;
                        if (isYB)
                        {
                            var orderlist = _ctx.BillOrders.IsStatus(OrderStatus.未支付).Where(m => m.CardNo == cardNo
                                                                       && m.ClinicNo == clinicNo 
                                                                       && m.YiBaoStatus != 2
                                                                       && !string.IsNullOrEmpty(m.YiBaoJydjh)).ToList();
                            foreach (var o in orderlist)
                            {
                                #region 取消医保

                                int ybstate = YbPayService.YbRefund(o.CardNo, o.YiBaoJydjh);
                                o.YiBaoStatus = ybstate == 1 ? 2 : 3;

                                #endregion
                            }
                            _ctx.SaveChanges();

                            #region 获取医保缴费信息

                            var getYBChargesRequest = new GetYBChargesRequest();
                            getYBChargesRequest.CardNo = cardNo;
                            getYBChargesRequest.ClinicNo = clinicNo;
                            getYBChargesRequest.Zfy = prescMoney;
                            GetYBChargesResponse ybResponse;

                            try
                            {
                                var httpClient = InHttpClient.GetClient();
                                var responseMsg =
                                    httpClient.PostAsJsonAsync("YBWs/GetYBCharges", getYBChargesRequest).Result;
                                responseMsg.EnsureSuccessStatusCode();
                                ybResponse = responseMsg.Content.ReadAsAsync<GetYBChargesResponse>().Result;
                            }
                            catch (Exception ex)
                            {
                                Logger.ErrorFormat("获取医保缴费信息Api出错,信息：{0}", JsonConvert.SerializeObject(ex));
                                prescriptionResponse.ErrMsg = "无法进行医保缴费，请到门诊缴费窗口进行缴费或在微信上以自费方式进行缴费";
                                return new ResResult<PrescriptionResponse>(Result.失败, prescriptionResponse);
                            }
                            if (ybResponse.ResultCode == "0")
                            {
                                decimal charges = 0;
                                decimal cost = 0;
                                decimal.TryParse(ybResponse.Charges, out charges);
                                decimal.TryParse(ybResponse.Costs, out cost);
                                if (charges < 0 || cost < 0 || (charges + cost != newBillOrder.PrescMoney))
                                {
                                    newBillOrder.Remark = "医保返回的金额出错";
                                    prescriptionResponse.YbError = "error";
                                    prescriptionResponse.ErrMsg = "无法进行医保缴费，请到门诊缴费窗口进行缴费或在微信上以自费方式进行缴费";
                                    //return new ResResult<PrescriptionResponse>(Result.失败, prescriptionResponse);
                                }

                                newBillOrder.YiBaoIndiId = ybResponse.IndiId;
                                newBillOrder.YiBaoJydjh = ybResponse.Jydjh;
                                newBillOrder.YiBaoStatus = 1;
                                newBillOrder.YibaoMoney = Convert.ToDecimal(ybResponse.Charges);
                                newBillOrder.PersonalMoney = Convert.ToDecimal(ybResponse.Costs);

                                prescriptionResponse.Costs = ybResponse.Costs;
                                prescriptionResponse.Charges = ybResponse.Charges;

                            }
                            else
                            {
                                newBillOrder.YiBaoStatus = 4;
                                newBillOrder.Remark = ybResponse.ResultDesc;
                                prescriptionResponse.YbError = "error";
                                prescriptionResponse.ErrMsg = "无法进行医保缴费，请到门诊缴费窗口进行缴费或在微信上以自费方式进行缴费";
                                return new ResResult<PrescriptionResponse>(Result.失败, prescriptionResponse);
                            }

                            #endregion
                        }

                        _ctx.BillOrders.Add(newBillOrder);
                        _ctx.SaveChanges();
                        #region 保存缴费单明细
                        foreach (var item in response.PrescItemList)
                        {
                            var newBillOrderItem = new BillOrderItem
                            {
                                BillOrderId = newBillOrder.Id,
                                Account = item.Account,
                                ItemPrice = item.ItemPrice.ToDecimalOrDefault(),
                                Money = item.Money.ToDecimalOrDefault(),
                                Name = item.ItemName,
                                Type = item.Type,
                                Unit = item.Unit
                            };
                            _ctx.BillOrderItems.Add(newBillOrderItem);
                        }
                        _ctx.SaveChanges();

                        prescriptionResponse.BillOrderId = newBillOrder.Id;
                        prescriptionResponse.BillOrderNo = newBillOrder.OrderNo;
                        prescriptionResponse.IsGetBillDetailInfoSucceed = true;

                        if (isYB)
                        {
                            // RMQ 16分钟后执行取消医保操作
                            var payFailedProducer = new OrderPayFailedProducer();
                            payFailedProducer.Publish(new OrderPayFailedMsg
                            {
                                OrderType = Rmq.Center.OrderType.门诊缴费订单,
                                OrderId = newBillOrder.Id,
                                OrderStatus = new[] {OrderStatus.未支付.ToInt32()}
                            }, 16*60*1000);
                        }
                        return new ResResult<PrescriptionResponse>(Result.成功, prescriptionResponse);
                        #endregion
                    }
                    else
                    {
                        prescriptionResponse.ErrMsg = "服务器或网络异常，请联系客服！";
                        return new ResResult<PrescriptionResponse>(Result.失败, prescriptionResponse);
                    }
                    #endregion
                }

            }
            else
            {
                prescriptionResponse.ErrMsg = "没有查询到您的缴费信息！";
                return new ResResult<PrescriptionResponse>(Result.失败, prescriptionResponse);
            }
        }


        /// <summary>
        /// 执行缴费支付操作 (前提： 微信支付状态为 未支付（0））
        /// </summary>
        public ResResult<string> Paying(string clientIp)
        {
            var payState = PayState.未付款.ToInt32().ToString();
            var order = _ctx.BillOrders.FirstOrDefault( x => x.Id == _orderId && x.PayState == payState);
            if (order != null)
            {
                order.OrderStatus = OrderStatus.支付中.ToInt32();
                _ctx.SaveChanges();
                // 费用为0时直接设置为支付成功
                if (order.PrescMoney== 0)
                {
                    PaySucceed(DateTime.Now, "0");
                    return new ResResult<string>(Result.成功, "", "");
                }
            }
            else
            {
                return new ResResult<string>(Result.条件不足未执行);
            }

            if (order.OrderStatus == OrderStatus.支付中.ToInt32())
            {

                // RMQ 16分钟后执行支付失败操作
                var payFailedProducer = new OrderPayFailedProducer();
                payFailedProducer.Publish(new OrderPayFailedMsg
                {
                    OrderType = Rmq.Center.OrderType.门诊缴费订单,
                    OrderId = order.Id,
                    OrderStatus = new[] {OrderStatus.支付中.ToInt32()}
                }, 16*60*1000);

                //组织 微信 js 支付方法 getBrandWCPayRequest 的参数
                var payStartTime = System.DateTime.Now.ToString("yyyyMMddHHmmss");
                var payExpireTime = System.DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss");

                var payFee = (order.PrescMoney*100).ToInt32().ToString();
                if (order.YiBaoStatus.HasValue && order.YiBaoStatus == 1)
                {
                    //医保类型，支付个人部分
                    payFee = (order.PersonalMoney * 100).ToInt32().ToString();
                }
                var superOpenIds = ConfigurationManager.AppSettings["OpenIdsForPayMin"]
                    .Split(" , ", StringSplitOptions.RemoveEmptyEntries);
                if (superOpenIds.Contains(order.OpenId))
                {
                    payFee = "1";
                }

                var payRequestParam = TenpayV2Helper.GenerateWxPayParameter("就诊缴费", "BL" + order.OrderNo,
                    payFee, clientIp, payStartTime, payExpireTime);

                return new ResResult<string>(Result.成功, payRequestParam, "");
            }
            else if (order.OrderStatus == OrderStatus.支付成功.ToInt32())
            {
                //执行HIS缴费,改为消息中心处理
                //DoPrescription();;
                var repostProducer = new OrderPickupingProducer();
                repostProducer.Publish(new OrderPickupingMsg
                {
                    OrderType = Rmq.Center.OrderType.门诊缴费订单,
                    OrderId = _orderId,
                    OrderStatus = new[] { OrderStatus.支付成功.ToInt32() }
                }, 1000);
                return new ResResult<string>(Result.失败, "订单已缴费成功", "");
            }
            else
            {
                return new ResResult<string>(Result.条件不足未执行);
            }
        }

        /// <summary>
        /// 取消缴费单支付
        /// </summary>
        public ResResult<string> CancelPay()
        {
            try
            {
                var order = _ctx.BillOrders.IsStatus(OrderStatus.未支付, OrderStatus.支付中).FirstOrDefault(
                    x => x.Id == _orderId);
                if (order != null)
                {
                    if (order.YiBaoStatus != null && order.YiBaoStatus == 1)
                    {
                        if (order.YiBaoJydjh.IsNotNullOrEmpty())
                        {
                            //医保状态，默认为取消失败
                            int ybstatus = YbPayService.YbRefund(order.CardNo, order.YiBaoJydjh);
                            order.YiBaoStatus = ybstatus == 1 ? 2 : 3;
                        }
                    }
                    order.OrderStatus = OrderStatus.支付失败.ToInt32();

                    _ctx.SaveChanges();

                }
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("取消缴费单失败,信息：{0}", JsonConvert.SerializeObject(ex));
                return new ResResult<string>(Result.失败,ex.Message);
            }

            return new ResResult<string>(Result.成功);
        }

        /// <summary>
        /// 执行缴费操作 （前提：订单状态为 支付成功（2））
        /// </summary>
        public ResResult<string> DoPrescription(bool autoFeedback = true)
        {
            var order = _ctx.BillOrders.IsStatus(OrderStatus.支付成功).FirstOrDefault(x => x.Id == _orderId );
            if (order != null)
            {
                order.OrderStatus = OrderStatus.缴费中.ToInt32();
                _ctx.SaveChanges();

            }
            else
            {
                return new ResResult<string>(Result.条件不足未执行);
            }

            if (order.YiBaoStatus != null && order.YiBaoStatus == 1)
            {
                #region 医保缴费
                var request = new ExeYBPrescriptionPayRequest();
                request.CardNo = order.CardNo;
                request.ClinicNo = order.ClinicNo;
                request.Zfy = order.PrescMoney.ToString();
                request.Charges = order.YibaoMoney.ToString();
                request.Costs = order.PersonalMoney.ToDecimalOrDefault().ToString();
                request.TransNo = order.WxTransactionId;
                request.TransTime = order.PayTime.GetValueOrDefault().ToString("yyyy-MM-dd HH:mm:ss");
                request.Jydjh = order.YiBaoJydjh;

                ExeYBPrescriptionPayResponse response;
                try
                {
                    var httpClient = InHttpClient.GetClient();
                    var responseMsg = httpClient.PostAsJsonAsync("YBWs/ExeYBPrescriptionPay", request).Result;
                    responseMsg.EnsureSuccessStatusCode();
                    response = responseMsg.Content.ReadAsAsync<ExeYBPrescriptionPayResponse>().Result;
                }
                catch (Exception ex)
                {
                    Logger.ErrorFormat("调用院内医保缴费Api出错,信息：{0}", JsonConvert.SerializeObject(ex));
                    // RMQ 执行缴费状态结果查询
                    var pickupingChkProducer = new OrderPickupingChkProducer();
                    pickupingChkProducer.Publish(new OrderPickupingChkMsg
                    {
                        OrderType = Rmq.Center.OrderType.门诊缴费订单,
                        OrderId = order.Id,
                        OrderStatus = new[] { OrderStatus.缴费中.ToInt32() }
                    });

                    return new ResResult<string>(Result.未返回);
                }

                //获取院内webservice信息时出现错误 (院内webservice层错误)
                if (response.ResultCode != "0")
                {
                    if (autoFeedback)
                    {
                        DoPrescriptionFail(response.ResultDesc);
                    }

                    return new ResResult<string>(Result.失败, response.ResultDesc);
                }
                else
                {
                    if (autoFeedback)
                    {
                        DoPrescriptionSuccess(response.DisWinList,response.ResultDesc);
                    }

                    return new ResResult<string>(Result.成功);
                }
                #endregion
            }
            else
            {
                #region 普通缴费
                //执行缴费操作
                var request = new ExePrescriptionPayRequest();
                request.CardNo = order.CardNo;
                request.PrescNo = order.ClinicNo;
                request.SumFee = order.PrescMoney.ToString();
                request.TransNo = order.WxTransactionId;
                request.TransTime = order.PayTime.GetValueOrDefault().ToString("yyyy-MM-dd HH:mm:ss");

                ExePrescriptionPayResponse response;
                try
                {
                    var httpClient = InHttpClient.GetClient();
                    var responseMsg = httpClient.PostAsJsonAsync("HisWs/ExePrescriptionPay", request).Result;
                    responseMsg.EnsureSuccessStatusCode();
                    response = responseMsg.Content.ReadAsAsync<ExePrescriptionPayResponse>().Result;
                }
                catch (Exception ex)
                {
                    Logger.ErrorFormat("调用院内获取医保Api出错,信息：{0}", JsonConvert.SerializeObject(ex));
                    // RMQ 执行缴费状态结果查询
                    var pickupingChkProducer = new OrderPickupingChkProducer();
                    pickupingChkProducer.Publish(new OrderPickupingChkMsg
                    {
                        OrderType = Rmq.Center.OrderType.门诊缴费订单,
                        OrderId = order.Id,
                        OrderStatus = new[] { OrderStatus.缴费中.ToInt32() }
                    });

                    return new ResResult<string>(Result.未返回);
                }

                //执行缴费失败
                if (response.ResultCode != "0")
                {
                    if (autoFeedback)
                    {
                        DoPrescriptionFail(response.ResultDesc);
                    }
                    return new ResResult<string>(Result.失败, response.ResultDesc);
                }
                //执行缴费成功
                else
                {
                    if (autoFeedback)
                    {
                        List<ExePrescriptionPaySubDisWinInfoResponse> diswin =new List<ExePrescriptionPaySubDisWinInfoResponse>();
                        response.DisWinList.ForEach(x => diswin.Add(new ExePrescriptionPaySubDisWinInfoResponse
                        {
                            DisWin = x.DisWin,
                            DisWinAdd = x.DisWinAdd,
                            RcptNo = x.RcptNo,
                            VisitNo = x.VisitNo
                        }));
                        DoPrescriptionSuccess(diswin, response.ResultDesc);
                    }
                    return new ResResult<string>(Result.成功);
                }
                #endregion
            }

        }

        /// <summary>
        /// 执行缴费成功处理
        /// </summary>
        public void DoPrescriptionSuccess(List<ExePrescriptionPaySubDisWinInfoResponse> diswin,string remark)
        {
            var order = _ctx.BillOrders.IsStatus(OrderStatus.缴费中).FirstOrDefault(x => x.Id == _orderId );
            if (order != null )
            {
                order.Remark = remark;
                order.OrderStatus = OrderStatus.缴费成功.ToInt32();
                if (diswin != null)
                {
                    foreach (var disWin in diswin)
                    {
                        var newBillOrderDisWin = new BillOrderDisWin
                        {
                            BillOrderId = order.Id,
                            DisWin = disWin.DisWin,
                            DisWinAdd = disWin.DisWinAdd,
                            RcptNo = disWin.RcptNo,
                            VisitNo = disWin.VisitNo
                        };
                        _ctx.BillOrderDisWins.Add(newBillOrderDisWin);
                    }

                }
                _ctx.SaveChanges();

                // TODO RMQ 发送用户挂号成功通知
                // TODO RMQ 发送发货通知

            }
        }

        /// <summary>
        /// 执行缴费失败处理
        /// </summary>
        public void DoPrescriptionFail(string remarik)
        {
            var order =
                _ctx.BillOrders.IsStatus(OrderStatus.缴费中).FirstOrDefault(x => x.Id == _orderId );
            if (order != null)
            {
                order.OrderStatus = OrderStatus.缴费失败.ToInt32();
                order.Remark = remarik;
                #region 发起医保退款

                if (order.YiBaoStatus.HasValue && order.YiBaoStatus == 1)
                {
                    if (order.YiBaoJydjh.IsNotNullOrEmpty())
                    {
                        int ybstatus = YbPayService.YbRefund(order.CardNo, order.YiBaoJydjh);
                        order.YiBaoStatus = ybstatus == 1 ? 2 : 3;
                    }
                }

                #endregion
                _ctx.SaveChanges();

                if (order.PrescMoney > 0)
                {
                    // RMQ 执行退费操作
                    var refundingProducer = new OrderRefundingProducer();
                    refundingProducer.Publish(new OrderRefundingMsg
                    {
                        OrderType = Rmq.Center.OrderType.门诊缴费订单,
                        OrderId = order.Id,
                        Reason = 1,
                        OrderStatus = new[] { OrderStatus.缴费失败.ToInt32() }
                    }, 1000);
                }

            }

        }

        ///  <summary>
        ///  缴费单支付成功的处理
        ///  </summary>
        /// <param name="payDt">支付成功时间</param>
        /// <param name="transactionId">支付交易号</param>
        public void PaySucceed(DateTime payDt, string transactionId)
        {
            var order = _ctx.BillOrders.IsStatus(OrderStatus.支付中).FirstOrDefault(x => x.Id == _orderId );
            if (order != null)
            {
                order.PayState = PayState.已付款.ToInt32().ToString();
                order.PayTime = payDt;
                order.WxTransactionId = transactionId;
                order.OrderStatus = OrderStatus.支付成功.ToInt32();
                _ctx.SaveChanges();

                //执行HIS缴费,改为消息中心处理
                //DoPrescription();;
                var repostProducer = new OrderPickupingProducer();
                repostProducer.Publish(new OrderPickupingMsg
                {
                    OrderType = Rmq.Center.OrderType.门诊缴费订单,
                    OrderId = _orderId,
                    OrderStatus = new[] { OrderStatus.支付成功.ToInt32() }
                }, 1000);
            }
        }

        /// <summary>
        /// 16分钟过后轮训订单状态，执行取消支付
        /// </summary>
        /// <returns></returns>
        public void PayFailed()
        {
            var order = _ctx.BillOrders.IsStatus(OrderStatus.支付中).FirstOrDefault(x => x.Id == _orderId);
            if (order != null)
            {
                order.OrderStatus = OrderStatus.支付失败.ToInt32();

                #region 发起医保退款,如果订单超时支付，则发起取消医保退款

                if (order.YiBaoStatus.HasValue && order.YiBaoStatus == 1)
                {
                    if (order.YiBaoJydjh.IsNotNullOrEmpty())
                    {
                        int ybstatus = YbPayService.YbRefund(order.CardNo, order.YiBaoJydjh);
                        order.YiBaoStatus = ybstatus == 1 ? 2 : 3;
                    }
                }

                #endregion

                _ctx.SaveChanges();

            }

        }

        /// <summary>
        /// 16分钟过后轮训订单状态，取消医保缴费
        /// </summary>
        /// <returns></returns>
        public void YbPayFailed()
        {
            var order = _ctx.BillOrders.IsStatus(OrderStatus.未支付).FirstOrDefault(x => x.Id == _orderId);
            if (order != null)
            {
                //order.OrderStatus = OrderStatus.支付失败.ToInt32();
                #region 发起医保退款,如果订单超时支付，则发起取消医保退款
                if (order.YiBaoStatus.HasValue && order.YiBaoStatus == 1)
                {
                    if (order.YiBaoJydjh.IsNotNullOrEmpty())
                    {
                        int ybstatus = YbPayService.YbRefund(order.CardNo, order.YiBaoJydjh);
                        order.YiBaoStatus = ybstatus == 1 ? 2 : 3;
                    }
                }
                #endregion
                _ctx.SaveChanges();

            }

        }



        /// <summary>
        /// 执行退费操作
        /// </summary>
        /// <param name="autoFeedback">是否自动做成功/失败数据处理</param>
        /// <returns></returns>
        public ResResult<RefundResult> Refunding(bool autoFeedback = true)
        {
            var order = _ctx.BillOrders.IsStatus(OrderStatus.缴费失败).FirstOrDefault(x => x.Id == _orderId);
            if (order != null)
            {
                order.OrderStatus = OrderStatus.退款中.ToInt32();
                order.PayState = PayState.退款中.ToInt32().ToString();

                _ctx.SaveChanges();
            }
            else
            {
                return new ResResult<RefundResult>(Result.条件不足未执行);
            }

            RefundResult refundResult;
            try
            {
                var paylog = _ctx.OrderNotifyLogs.OrderByDescending(x => x.Id).FirstOrDefault(x => x.OutTradeNo == "BL" + order.OrderNo);
                var refundAmount = (order.PrescMoney * 100).ToInt32();
                if (order.YiBaoStatus.HasValue && order.YiBaoStatus == 1)
                {
                    //医保类型，支付个人部分
                    refundAmount = (order.PersonalMoney * 100).ToInt32();
                }
                //医生改单后扫码支付造成金额不一致，导致缴费退款取用户实际缴费金额
                if (paylog != null && paylog.TotalFee.ToInt32OrDefault() != refundAmount)
                {
                    refundAmount = paylog.TotalFee.ToInt32OrDefault();
                }
                refundResult = TenpayV2Helper.DoRefund(order.OpenId, "BL" + order.OrderNo, order.WxTransactionId,
                 "BL" + order.OrderNo, refundAmount.ToInt32(), refundAmount.ToInt32());
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用第三方支付退款Api出错,信息：{0}", JsonConvert.SerializeObject(ex));
                return new ResResult<RefundResult>(Result.未返回);
            }
            //退款成功 4,10
            //退款处理中 8 9 11
            if (refundResult.RefundStatus == 4 || refundResult.RefundStatus == 10 ||
                refundResult.RefundStatus == 8 || refundResult.RefundStatus == 9 || refundResult.RefundStatus == 11)
            {
                if (autoFeedback)
                {
                    RefundSucceed(refundResult);
                }

                return new ResResult<RefundResult>(Result.成功, refundResult);
            }
            //退款失败 3，5，6
            //转入代发 7
            if (refundResult.RefundStatus == 7 ||
                refundResult.RefundStatus == 3 || refundResult.RefundStatus == 5 || refundResult.RefundStatus == 6)
            {
                if (autoFeedback)
                {
                    RefundFailed();
                }
                return new ResResult<RefundResult>(Result.失败, refundResult, "");
            }

            return new ResResult<RefundResult>(Result.未返回);
        }


        /// <summary>
        /// 退费成功的处理
        /// </summary>
        /// <param name="resultResult"></param>
        public void RefundSucceed(RefundResult resultResult)
        {
            var order = _ctx.BillOrders.IsStatus(OrderStatus.退款中).FirstOrDefault(x => x.Id == _orderId);
            if (order != null)
            {
                order.OrderStatus = OrderStatus.退款成功.ToInt32();
                order.PayState = PayState.已退款.ToInt32().ToString();
                order.RefundTime = DateTime.Now;
                order.WxRefundId = resultResult.RefundId;
                _ctx.SaveChanges();


                //TODO RMQ 发送用户退费成功通知
                //TODO RMQ 发送发货通知，发货失败

            }
        }

        /// <summary>
        /// 退费失败的处理
        /// </summary>
        public void RefundFailed()
        {
            var order = _ctx.BillOrders.IsStatus(OrderStatus.退款中).FirstOrDefault(x => x.Id == _orderId);
            if (order != null)
            {
                order.OrderStatus = OrderStatus.退款失败.ToInt32();
                order.PayState = PayState.退款失败.ToInt32().ToString();
                _ctx.SaveChanges();

                //TODO RMQ 发送发货通知，发货失败
            }

        }



        /// <summary>
        /// 执行缴费订单查询操作
        /// </summary>
        /// <param name="autoFeedback">是否自动做成功/失败数据处理</param>
        /// <returns></returns>
        public ResResult<GetPayStatusResponse> BillPayStatusChk(bool autoFeedback = true)
        {
            var order = _ctx.BillOrders.IsStatus(OrderStatus.缴费中).FirstOrDefault(x => x.Id == _orderId );

            if (order == null)
            {
                return new ResResult<GetPayStatusResponse>(Result.条件不足未执行);
            }

            var request = new GetPayStatusRequest();
            request.CardNo = order.CardNo;
            request.ClinicNo = order.ClinicNo;

            GetPayStatusResponse response;

            try
            {
                var httpClient = InHttpClient.GetClient();
                var responseMsg = httpClient.PostAsJsonAsync("HisWs/GetPayStatus", request).Result;
                responseMsg.EnsureSuccessStatusCode();
                response = responseMsg.Content.ReadAsAsync<GetPayStatusResponse>().Result;
            }
            catch (Exception ex)
            {
                Logger.ErrorFormat("调用院内查询缴费单状态Api出错,信息：{0}", JsonConvert.SerializeObject(ex));
                return new ResResult<GetPayStatusResponse>(Result.未返回);
            }

            if (response.ResultCode != "0")
            {
                //如果查询结果异常，则返回未返回状态，等待下一次轮训
                return new ResResult<GetPayStatusResponse>(Result.未返回);
            }
            else
            {
                //缴费状态为 已支付
                if (response.Status == "0")
                {
                    if (autoFeedback)
                    {
                        List<ExePrescriptionPaySubDisWinInfoResponse> diswin =
                            new List<ExePrescriptionPaySubDisWinInfoResponse>();
                        response.DisWinList.ForEach(x => diswin.Add( new ExePrescriptionPaySubDisWinInfoResponse
                        {
                            DisWin = x.DisWin,
                            DisWinAdd = x.DisWinAdd,
                            RcptNo = x.RcptNo,
                            VisitNo = x.VisitNo
                        }));
   
                        DoPrescriptionSuccess(diswin,response.ResultDesc);
                    }
                }
                //缴费状态为 未支付
                if (response.Status == "1")
                {
                    if (autoFeedback)
                    {
                        DoPrescriptionFail(response.ResultDesc);
                    }
                }
                return new ResResult<GetPayStatusResponse>(Result.成功, response);
            }

        } 


        /// <summary>
        /// 资源释放
        /// </summary>
        public void Dispose()
        {
            _ctx.Dispose();
        }
    }

    public static class BillOrderExtensions
    {
        public static IQueryable<BillOrder> IsOpenId(this IQueryable<BillOrder> source, string openId)
        {
            if (string.IsNullOrEmpty(openId))
            {
                return source;
            }

            return source.Where(x => x.OpenId == openId);
        }

        public static IQueryable<BillOrder> IsStatus(this IQueryable<BillOrder> source,
            params BizBillOrder.OrderStatus[] orderStatuses)
        {
            Expression<Func<BillOrder, bool>> expression = x => true;

            foreach (var orderStatus in orderStatuses)
            {
                var intOrderStatus = (int)orderStatus;
                Expression<Func<BillOrder, bool>> exp = x => x.OrderStatus == intOrderStatus;
                var body = Expression.OrElse(expression.Body, exp.Body);
                expression = Expression.Lambda<Func<BillOrder, bool>>(body, expression.Parameters[0]);
            }

            return source.Where(expression);
        }

    }


    public class PrescriptionResponse
    {
        public bool IsGetBillDetailInfoSucceed { get; set; }

        public string ErrMsg { get; set; }

        public string YbError { get; set; }

        public string Costs { get; set; }

        public string Charges { get; set; }

        public int BillOrderId { get; set; }

        public string BillOrderNo { get; set; }

        /// <summary>
        /// 缴费单项列表
        /// </summary>
        public List<GetPrescriptionDetailResponse.PrescItemInfo> PrescItemList { get; set; }


    }
}
